<?php

namespace Wxwork\CallBack;

use Exception;
use Wxwork\CallBack\Response\CallBackResponse;
use Wxwork\CallBack\Response\CancelAuth;
use Wxwork\CallBack\Response\ChangeAuth;
use Wxwork\CallBack\Response\CreateAuth;
use Wxwork\CallBack\Response\EventResponse;
use Wxwork\CallBack\Response\SuiteTicket;
use Wxwork\Common\AESEncrypt;
use Wxwork\Common\XMLParse;

/**
 * 回调配置
 */
class CallBack
{
    /**
     * 回调配置的 Token
     * token
     * @var  $token
     */
    private $token;

    /**
     * 回调配置的 EncodingAESKey
     * encodingAESKey
     * @var  $encodingAESKey
     */
    private $encodingAESKey;

    private $corpId;

    private $suiteId;

    public function __construct(array $config)
    {
        $this->token = $config['token'] ?? '';
        $this->encodingAESKey = $config['encodingAesKey'] ?? '';
        $this->corpId = $config['corpId'] ?? '';
        $this->suiteId = $config['suiteId'] ?? '';

    }

    /**
     * 验证回调URL
     * @param $verifyMsg
     * @param $verifyTimestamp
     * @param $verifyNonce
     * @param $verifyEchoStr
     * @return string
     * @throws Exception
     */
    public function verifyURL($verifyMsg, $verifyTimestamp, $verifyNonce, $verifyEchoStr, $corpId = ''): string
    {
        if (strlen($this->encodingAESKey) != 43) {
            throw new Exception('sha加密生成签名失败');
        }

        //签名验证
        $array = array($this->token, $verifyTimestamp, $verifyNonce, $verifyEchoStr);
        sort($array, SORT_STRING);
        $str = implode($array);
        $signature = sha1($str);

        if ($signature != $verifyMsg) {
            throw new Exception('签名验证错误');
        }

        //解密
        $encrypt = new AESEncrypt($this->encodingAESKey);

        return $encrypt->decrypt($verifyEchoStr, $corpId ? $corpId : $this->corpId);
    }

    /**
     * 指令回调解析
     * @param $verifyMsg
     * @param $verifyTimestamp
     * @param $verifyNonce
     * @param $verifyData
     * @return CallBackResponse
     * @throws Exception
     */
    public function callbackMsg($verifyMsg, $verifyTimestamp, $verifyNonce, $verifyData, $suiteId = ''): CallBackResponse
    {
        if (strlen($this->encodingAESKey) != 43) {
            throw new Exception('sha加密生成签名失败');
        }

        $xml = XMLParse::xmlToArr($verifyData);

        $verifyEchoStr = $xml['Encrypt'] ?? '';

        //验证签名
        $array = array($this->token, $verifyTimestamp, $verifyNonce, $verifyEchoStr);
        sort($array, SORT_STRING);
        $str = implode($array);
        $signature = sha1($str);

        if ($signature != $verifyMsg) {
            throw new Exception('签名验证错误');
        }
        //解密
        $encrypt = new AESEncrypt($this->encodingAESKey);

        $decryptMsg = $encrypt->decrypt($verifyEchoStr, $suiteId ? $suiteId : $this->suiteId);
        $decryptMsg = XMLParse::xmlToArr($decryptMsg);

        $type = $decryptMsg['InfoType'] ?? '';

        switch ($type) {
            case 'suite_ticket':
                return new SuiteTicket($decryptMsg);
            case 'create_auth':
                return new CreateAuth($decryptMsg);
            case 'cancel_auth':
                return new CancelAuth($decryptMsg);
            case 'change_auth':
                return new ChangeAuth($decryptMsg);
        }
        return new CallBackResponse($decryptMsg);
    }

    /**
     * 事件推送
     * @param $verifyMsg
     * @param $verifyTimestamp
     * @param $verifyNonce
     * @param $verifyData
     * @return EventResponse
     * @throws Exception
     */
    public function eventMsg($verifyMsg, $verifyTimestamp, $verifyNonce, $verifyData, $corpid = ''): EventResponse
    {
        if (strlen($this->encodingAESKey) != 43) {
            throw new Exception('sha加密生成签名失败');
        }

        $xml = XMLParse::xmlToArr($verifyData);

        $verifyEchoStr = $xml['Encrypt'] ?? '';

        //验证签名
        $array = array($this->token, $verifyTimestamp, $verifyNonce, $verifyEchoStr);
        sort($array, SORT_STRING);
        $str = implode($array);
        $signature = sha1($str);

        if ($signature != $verifyMsg) {
            throw new Exception('签名验证错误');
        }
        //解密
        $encrypt = new AESEncrypt($this->encodingAESKey);

        $decryptMsg = $encrypt->decrypt($verifyEchoStr, $corpid ? $corpid : $this->corpId);

        $decryptMsg = XMLParse::xmlToArr($decryptMsg);

        $type = $decryptMsg['InfoType'] ?? '';

        return new EventResponse($decryptMsg);
    }

}
